package net.yuyoo.uusession;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import net.yuyoo.uusession.util.TimeoutConcurrentHashMap;
import net.yuyoo.uusession.util.TimeoutListener;
import net.yuyoo.uusession.util.Timeoutable;

public class UULocalSession implements Timeoutable, TimeoutListener {

	private static TimeoutConcurrentHashMap validSessions = new TimeoutConcurrentHashMap(2 * 60 * 1000L, 1000);
	private static List invalidSessions = Collections.synchronizedList(new LinkedList());
	
	private static int maxStandbySessions = 5000;
	
	private UUSession uusession = null;
	private long createTime = -1L;
	private int maxInactiveInterval = -1;
	
		 
	private String id = null;
	private long expiring = 0L;
	private long timeout = 0L;
	private boolean isDelay = true; 
	private boolean isNew = true;
	
	
	
	Map cache = new ConcurrentHashMap();
		 
	private UULocalSession(UUSession uusession) {
		 		
		this.uusession = uusession;
		
		this.id = this.uusession.getId();
		
		this.createTime = this.uusession.getCreateTime();
		this.maxInactiveInterval = this.uusession.getMaxInactiveInterval();
		
		this.timeout = this.uusession.getExpiryTime().getTime();
		this.expiring = this.uusession.getSessionServer().getSessionTimeout();
		
		this.syncLocalSession(this.uusession);
	}
	
	public static UULocalSession getLocalSession(UUSession uusession) {

		if (null == uusession) {
			throw new IllegalArgumentException();
		}
		
		String id = uusession.getId();
		
		UULocalSession rtv = (UULocalSession) validSessions.get(id);
		if (null == rtv) {
			if (invalidSessions.size() > 0) {
				rtv = (UULocalSession) invalidSessions.remove(0);
			} else {
				rtv = new UULocalSession(uusession);
			}
			validSessions.put(id, rtv);
		} else {
			rtv.isNew = false;
		}
		return rtv;
	} 
	
	public UUSession getUUSession() {
		return this.uusession;
	}
	
	public Enumeration getAttributeNames() {  
		
		Iterator<String> it = this.cache.keySet().iterator();
		List<String> r = new ArrayList<String>();
		while (it.hasNext()) {
			r.add(it.next());
		}
		return Collections.enumeration(r);
	}
	
	public String getId() {
		return this.id;
	}
	
	public long getCreateTime() {
		return this.createTime;
	}
	
	public int getMaxInactiveInterval() {
		
		return this.maxInactiveInterval;
	}
	
	public Object getAttribute(String key) {
		
		return this.cache.get(key);
	}
	
	public void setAttribute(String key, Object value) {
		this.cache.put(key, value);
	}
	
	public Object removeAttribute(String key) {
		
		return this.cache.remove(key);
	}
	
	public void invalidate() {
		this.cache.clear();
		validSessions.remove(this.id);
	}
	
	public long getExpiringTime() {
		return this.expiring;
	}

	public long getTimeout() {

		return this.timeout;
	}

	public boolean isDelay() {
		return this.isDelay;
	}

	public void setDelay(boolean flag) {
		this.isDelay = flag;
	}

	public void setExpiringTime(long expiring) {
		if (expiring > 0) {
			this.expiring = expiring;
		}
	}

	public void setTimeout(long time) {
		
		if (time > 0) {
			this.timeout = time;
		}
	}
	
	public boolean isNew() {
		
		return this.isNew;
	}

	public Object handle(Object key, Object value) { 
		
		UULocalSession session = (UULocalSession)value;
		session.cache.clear();
		if (invalidSessions.size() < maxStandbySessions) {
			invalidSessions.add(value);
		}
		return value;
	}
	
	private void syncLocalSession(UUSession s) {
		
		Enumeration e = s.getAttributeNames();
		String current = null;
		Object value = null;
		while (e.hasMoreElements()) {
			current = (String) e.nextElement();
			value = s.getAttribute(current);
			this.cache.put(current, value);
		}
	}
}
